home *** CD-ROM | disk | FTP | other *** search
/ System Booster / System Booster.iso / CD-ROM Tools / MCDPlayer / Source / mcdplayer.c < prev    next >
C/C++ Source or Header  |  1996-09-26  |  37KB  |  1,207 lines

  1. #include "mcdplayer.h"
  2.  
  3. char *version = "\0$VER: MCDPlayer " VERSION " (" __DATE__ " " __TIME__ ")";
  4.  
  5. UBYTE *scsi_data = NULL;
  6. UBYTE *toc_buf = NULL;
  7.  
  8. UBYTE *scsi_dev = NULL;
  9. int    scsi_id = 1;
  10.  
  11. UBYTE buffer[LINE_BUF];
  12.  
  13. int   ActStat = 0;   /* 0=No Disk; 1=Playing; 2=Stopped; 3=Paused; 4=Datadisk */
  14. int   ActTitle = 0;
  15. int   ActProg = 0;   /* -1=No Prog; 0=Default Prog; 1-3=other Progs */
  16. int   ActProgTitle = 0;
  17.  
  18. char  SetNextTitle = 0;
  19. char  InputTitleStat = 0; /* 0: direkte Titelwahl, 1: Zehnerstelle, 2: Einerstelle */
  20. int   InputTitle = 0;
  21.  
  22. MSGPORT *mp_ptr;
  23. IOSTDREQ *io_ptr;
  24. SCSICMD scsi_cmd;
  25. UBYTE *scsi_sense;
  26.  
  27. UBYTE TOC_NumTracks = 0;
  28. UBYTE TOC_Flags[100]; /* 0=Musik, 1=Daten */
  29. ULONG TOC_Addr[100];
  30. char *TOC_Title[100];
  31. char *TOC_CDTitle;
  32. char *TOC_CDInterpret;
  33. char  TOC_TitleStrs[4000];
  34. char  TOC_CDID[20];
  35.  
  36. char WndPosition = 0;
  37.  
  38. char *SongPath = NULL;
  39.  
  40. struct timerequest *TimerIO = NULL;
  41. struct MsgPort     *TimerMP = NULL;
  42. struct MsgPort     *BrokerMP = NULL;
  43. struct DiskObject  *DObj=NULL;
  44. struct Library     *CxBase= NULL;
  45.  
  46. CxObj *broker=NULL, *filter[17], *sender[17], *translate[17];
  47. struct NewBroker newbroker =
  48.      { NB_VERSION,
  49.        "MCDP",
  50.        "MultiCDPlayer, ©1994 Boris Jakubaschk",
  51.        "Player for audio CDs in a CDROM drive",
  52.        NBU_UNIQUE | NBU_NOTIFY,
  53.        NULL,
  54.        0, 0, 0 };
  55. ULONG cxsigflag;
  56.  
  57.  
  58. int TimerInit()
  59.     {
  60.     if (TimerMP = CreatePort(0,0))
  61.         {
  62.         if (TimerIO = (struct timerequest *) CreateExtIO(TimerMP, sizeof(struct timerequest)))
  63.             {
  64.             if (OpenDevice( TIMERNAME, UNIT_VBLANK, (struct IORequest *)TimerIO, 0L)==NULL)
  65.                 {
  66.                 return( 1 );
  67.                 }
  68.             else
  69.                 {
  70.                 ErrorMsg("Kann Timer.device nicht öffnen");
  71.                 }
  72.             }
  73.         else
  74.             {
  75.             ErrorMsg( "CreateExtIO fehlgeschlagen" );
  76.             }
  77.         }
  78.     else
  79.         {
  80.         ErrorMsg("CreatePort fehlgeschlagen");
  81.         }
  82.     return( 0 );
  83.     }
  84.  
  85. void TimerExit()
  86.     {
  87.     if (TimerIO)
  88.         {
  89.         CloseDevice((struct IORequest *)TimerIO);
  90.         DeleteExtIO((struct IORequest *)TimerIO);
  91.         };
  92.     if (TimerMP)
  93.         {
  94.         DeletePort(TimerMP);
  95.         };
  96.     }
  97.  
  98. int DoScsiCmd (UBYTE * data, int datasize, UBYTE * cmd, int cmdsize, UBYTE flags)
  99.     {
  100.     io_ptr->io_Length = sizeof (SCSICMD);
  101.     io_ptr->io_Data = (APTR) & scsi_cmd;
  102.     io_ptr->io_Command = HD_SCSICMD;
  103.  
  104.     scsi_cmd.scsi_Data = (APTR) data;
  105.     scsi_cmd.scsi_Length = datasize;
  106.     scsi_cmd.scsi_SenseActual = 0;
  107.     scsi_cmd.scsi_SenseData = scsi_sense;
  108.     scsi_cmd.scsi_SenseLength = SENSE_LEN;
  109.     scsi_cmd.scsi_Command = cmd;
  110.     scsi_cmd.scsi_CmdLength = cmdsize;
  111.     scsi_cmd.scsi_Flags = flags;
  112.  
  113.     (void) DoIO ((struct IORequest *) io_ptr);
  114.  
  115.     return (io_ptr->io_Error);
  116.     }
  117.  
  118. char SCMD_Inquiry ( void )
  119.     {
  120.     static SCSICMD6 command =
  121.         {
  122.         SCSI_CMD_INQ,
  123.         PAD,
  124.         PAD,
  125.         PAD,
  126.         0,
  127.         PAD
  128.         };
  129.     static int err;
  130.  
  131.     command.b4 = MAX_DATA_LEN;
  132.  
  133.     if ((err = DoScsiCmd ((UBYTE *) scsi_data, MAX_DATA_LEN,
  134.                           (UBYTE *) & command, sizeof (command),
  135.                           (SCSIF_READ | SCSIF_AUTOSENSE))) == 0)
  136.         {
  137.         return ((scsi_data[0] & 0x1F)==0x05);
  138.         }
  139.     return( FALSE );
  140.     }
  141.  
  142. void SCMD_PlayAudio (int starttrack)
  143.     {
  144.     static SCSICMD12 command =
  145.         {
  146.         SCSI_CMD_PLAYAUDIO12,
  147.         PAD,
  148.         0, 0, 0, 0,
  149.         0, 0, 0, 0,
  150.         PAD,
  151.         PAD,
  152.         };
  153.  
  154.     int   i = 1;
  155.     ULONG Addr;
  156.  
  157.     SetNextTitle = 0;
  158.  
  159.     if (ActProg != -1)
  160.         {
  161.         if (Program[0][ActProg]!=0)
  162.             {
  163.             while ( (i<starttrack) && (Program[i-1][ActProg]!=0) ) i++;
  164.             ActProgTitle = i;
  165.             starttrack = Program[i-1][ActProg];
  166.             }
  167.         else ActProg = -1;
  168.         }
  169.  
  170.     DrawPrgmSymb( (ActProg!=-1)?1:0 );
  171.  
  172.     while( (TOC_Flags[starttrack-1]==1)&&(starttrack<TOC_NumTracks) ) starttrack++;
  173.  
  174.     Addr = TOC_Addr[starttrack-1]+1;
  175.  
  176.     command.b2 = (Addr&0xFF000000)>>24;
  177.     command.b3 = (Addr&0x00FF0000)>>16;
  178.     command.b4 = (Addr&0x0000FF00)>>8;
  179.     command.b5 = (Addr&0x000000FF);
  180.  
  181.     if (ActProg == -1)
  182.         {
  183.         Addr = TOC_Addr[TOC_NumTracks]-TOC_Addr[starttrack-1]-1;
  184.         }
  185.     else Addr = TOC_Addr[starttrack]-TOC_Addr[starttrack-1]-1;
  186.  
  187.     command.b6 = (Addr&0xFF000000)>>24;
  188.     command.b7 = (Addr&0x00FF0000)>>16;
  189.     command.b8 = (Addr&0x0000FF00)>>8;
  190.     command.b9 = (Addr&0x000000FF);
  191.  
  192.     DoScsiCmd ((UBYTE *) scsi_data, MAX_DATA_LEN,
  193.                (UBYTE *) & command, sizeof (command),
  194.                (SCSIF_READ | SCSIF_AUTOSENSE));
  195.     };
  196.  
  197. void SCMD_PauseResume( void )
  198.     {
  199.     static SCSICMD10 command =
  200.         {
  201.         SCSI_CMD_PAUSERESUME,
  202.         PAD,
  203.         0,
  204.         0,
  205.         0,
  206.         0,
  207.         0,
  208.         0,
  209.         0,
  210.         PAD,
  211.         };
  212.  
  213.     command.b8 = (ActStat==1)?0x00:0x01;
  214.  
  215.     DoScsiCmd (0, 0,
  216.            (UBYTE *) & command, sizeof (command),
  217.            (SCSIF_READ | SCSIF_AUTOSENSE));
  218.     DrawPrgmSymb( (ActStat==1)?3:1 );
  219.     }
  220.  
  221. void SCMD_Eject( void )
  222.     {
  223.     static SCSICMD6 command =
  224.         {
  225.         SCSI_CMD_SSU,
  226.         0,
  227.         PAD,
  228.         PAD,
  229.         0,
  230.         PAD,
  231.         };
  232.  
  233.     int err;
  234.  
  235.     command.b4 = 2;
  236.  
  237.     if ((err = DoScsiCmd (0, 0,
  238.             (UBYTE *) & command, sizeof (command),
  239.             (SCSIF_READ | SCSIF_AUTOSENSE))) != 0)
  240.         {
  241.         return;
  242.         }
  243.     }
  244.  
  245. void SCMD_Stop( void )
  246.     {
  247.     static SCSICMD6 command =
  248.         {
  249.         SCSI_CMD_SSU,
  250.         0,
  251.         PAD,
  252.         PAD,
  253.         0,
  254.         PAD,
  255.         };
  256.  
  257.     command.b4 = 0;
  258.  
  259.     DoScsiCmd (0, 0,
  260.            (UBYTE *) & command, sizeof (command),
  261.            (SCSIF_READ | SCSIF_AUTOSENSE));
  262.     DrawPrgmSymb( 0 );
  263.     ActProg = -1;
  264.     SetDispStat();
  265.     }
  266.  
  267. void SCMD_SetVolume (int vol0, int vol1, int vol2, int vol3)
  268.     {
  269.     static int err, i, j;
  270.     static SCSICMD6 modecommand;
  271.     static struct volmodedata
  272.         {
  273.         UBYTE head[4];
  274.         UBYTE page;    /* page code 0x0E */
  275.         UBYTE plength;    /* page length */
  276.         UBYTE b2;        /* bit 2: Immed, bit 1: SOTC */
  277.         UBYTE b3;        /* reserved */
  278.         UBYTE b4;        /* reserved */
  279.         UBYTE b5;        /* bit 7: APRVal, bit 3-0: format of LBAs / Sec. */
  280.         UWORD bps;    /* logical blocks per second audio playback */
  281.         UBYTE out0;    /* lower 4 bits: output port 0 channel selection */
  282.         UBYTE vol0;    /* output port 0 volume */
  283.         UBYTE out1;    /* lower 4 bits: output port 1 channel selection */
  284.         UBYTE vol1;    /* output port 1 volume */
  285.         UBYTE out2;    /* lower 4 bits: output port 2 channel selection */
  286.         UBYTE vol2;    /* output port 2 volume */
  287.         UBYTE out3;    /* lower 4 bits: output port 3 channel selection */
  288.         UBYTE vol3;    /* output port 3 volume */
  289.         } modedata;
  290.  
  291.     for (i = 0; i < 4; i++)
  292.         modedata.head[i] = 0;
  293.  
  294.     modecommand.opcode    = SCSI_CMD_MSE;
  295.     modecommand.b1    = 0;
  296.     modecommand.b2    = 0x0E;
  297.     modecommand.b3    = 0;
  298.     modecommand.b4    = MAX_DATA_LEN;
  299.     modecommand.control    = 0;
  300.  
  301.     if ((err = DoScsiCmd ((UBYTE *) scsi_data, MAX_DATA_LEN,
  302.                           (UBYTE *) &modecommand, sizeof (modecommand),
  303.                           (SCSIF_READ | SCSIF_AUTOSENSE))) != 0)
  304.         return;
  305.  
  306.     for (j = (scsi_data[0]+1), i = scsi_data[3] + 4; i < j; i += scsi_data[i+1] + 2)
  307.         {
  308.         memcpy (&modedata.page, &scsi_data[i], 16);
  309.         }
  310.  
  311.     if (vol0 > -1 || vol1 > -1 || vol2 > -1 || vol3 > -1)
  312.         {
  313.         modedata.page = 0x0e;
  314.         modedata.plength = 0x0e;
  315.  
  316.         if (vol0 >= 0)
  317.             modedata.vol0 = vol0;
  318.         if (vol1 >= 0)
  319.             modedata.vol1 = vol1;
  320.         if (vol2 >= 0)
  321.             modedata.vol2 = vol2;
  322.         if (vol3 >= 0)
  323.             modedata.vol3 = vol3;
  324.  
  325.         modecommand.opcode    = SCSI_CMD_MSL;
  326.         modecommand.b1        = 0x10;
  327.         modecommand.b2        = 0;
  328.         modecommand.b3        = 0;
  329.         modecommand.b4        = sizeof (modedata);
  330.         modecommand.control    = 0;
  331.  
  332.         if ((err = DoScsiCmd ((UBYTE *) &modedata, sizeof(modedata),
  333.                               (UBYTE *) &modecommand, sizeof (modecommand),
  334.                               (SCSIF_WRITE | SCSIF_AUTOSENSE))) != 0)
  335.             return;
  336.         }
  337.     }
  338.  
  339. char *GetNextStr( char *a )
  340.     {
  341.     char *b;
  342.  
  343.     b = a;
  344.     while( *b!='\n' ) b++;
  345.     *b = '\0';
  346.     return( b+1 );
  347.     }
  348.  
  349. void ShowCDTitle( void )
  350.     {
  351.     int slen;
  352.  
  353.     SetAPen( MainWnd->RPort, 1 );
  354.     RectFill( MainWnd->RPort, 25, 38+offy, 258, 64+offy );
  355.     SetAPen( MainWnd->RPort, 2 );
  356.     SetBPen( MainWnd->RPort, 1 );
  357.     Move( MainWnd->RPort, 25, 50+offy );
  358.     slen = strlen(TOC_CDInterpret);
  359.     Text( MainWnd->RPort, TOC_CDInterpret, (slen>29)? 29:slen );
  360.     Move( MainWnd->RPort, 25, 61+offy );
  361.     slen = strlen(TOC_CDTitle);
  362.     Text( MainWnd->RPort, TOC_CDTitle, (slen>29)? 29:slen );
  363.  
  364.     ActTitle = 0;
  365.     }
  366.  
  367.  
  368. void SCMD_ReadTOC ( void )
  369.     {
  370.     static SCSICMD10 command =
  371.         {
  372.         SCSI_CMD_READTOC,
  373.         0,
  374.         PAD, PAD, PAD, PAD,
  375.         0,
  376.         0x03, 0x24,
  377.         PAD
  378.         };
  379.  
  380.     int err, tocsize;
  381.     int i;
  382.     UBYTE *tocptr;
  383.     char Buffer[130];
  384.     BPTR FH;
  385.     char *a;
  386.  
  387.     if ((err = DoScsiCmd ((UBYTE *) toc_buf, MAX_TOC_LEN,
  388.               (UBYTE *) & command, sizeof (command),
  389.               (SCSIF_READ | SCSIF_AUTOSENSE))) == 0)
  390.         {
  391.         SetAPen( MainWnd->RPort, 1 );
  392.         RectFill( MainWnd->RPort, 25, 38+offy, 258, 64+offy );
  393.  
  394.         tocsize = (toc_buf[0] << 8) | toc_buf[1];        /* first word encodes length */
  395.  
  396.         /* TOC_NumTracks = toc_buf[3]; */
  397.         TOC_Addr[2] = 0;
  398.         TOC_NumTracks = 0;
  399.         if (tocsize >= 2)    /* TOC Data Length - FTN - LTN */
  400.         tocsize -= 2;
  401.         for (tocptr = &toc_buf[4]; tocptr < (&toc_buf[4] + tocsize); tocptr += 8)
  402.         {
  403.             TOC_Addr[TOC_NumTracks] = (tocptr[4] << 24) | (tocptr[5] << 16) | (tocptr[6] << 8) | (tocptr[7]);
  404.         /* printf ("Track number: %d ", tocptr[2]); */
  405.         TOC_Flags[TOC_NumTracks] = (tocptr[1] & 0x04) ? 1 : 0;
  406.             TOC_NumTracks++;
  407.         }
  408.         TOC_NumTracks--;
  409.  
  410.         if (TOC_NumTracks<=20) RectFill( MainWnd->RPort, 165-7*(20-TOC_NumTracks), 65+offy, 190, 72+offy );
  411.  
  412.         SetAPen( MainWnd->RPort, 2 );
  413.         SetBPen( MainWnd->RPort, 1 );
  414.  
  415.         sprintf(Buffer, "%02d", TOC_Addr[TOC_NumTracks]/75/60 );
  416.      Move( MainWnd->RPort, 212, 37+offy );
  417.      Text( MainWnd->RPort, Buffer, 2 );
  418.  
  419.         sprintf(Buffer, "%02d", (TOC_Addr[TOC_NumTracks]/75)%60 );
  420.      Move( MainWnd->RPort, 231, 37+offy );
  421.      Text( MainWnd->RPort, Buffer, 2 );
  422.  
  423.         sprintf( TOC_CDID, "ID%02d%06X%06X", TOC_NumTracks, TOC_Addr[2], TOC_Addr[TOC_NumTracks] );
  424.  
  425.         sprintf( Buffer, SongPath );
  426.         AddPart( Buffer, TOC_CDID, 130 );
  427.  
  428.         if (FH = Open( Buffer, MODE_OLDFILE ))
  429.             {
  430.             Read( FH, TOC_TitleStrs, 4000 );
  431.             Close( FH );
  432.             a = TOC_TitleStrs;
  433.             TOC_CDInterpret = a;
  434.             a = GetNextStr( a );
  435.             TOC_CDTitle = a;
  436.             for (i=0; i<TOC_NumTracks; i++)
  437.                 {
  438.                 a = GetNextStr( a );
  439.                 TOC_Title[i] = a;
  440.                 };
  441.             a = GetNextStr( a );
  442.             }
  443.         else
  444.             {
  445.             a = TOC_TitleStrs;
  446.             strcpy( a, "<unbekannte CD>" );
  447.             TOC_CDTitle = a;
  448.             a += strlen( a ) + 1;
  449.             strcpy( a, TOC_CDID );
  450.             TOC_CDInterpret = a;
  451.             a += strlen( a ) + 1;
  452.             for (i=0; i<TOC_NumTracks; i++)
  453.                 {
  454.                 strcpy( a, "<unbekannter Titel>" );
  455.                 TOC_Title[i] = a;
  456.                 a += strlen( a ) + 1;
  457.                 };
  458.             };
  459.         ShowCDTitle();
  460.         GetProgram();
  461.         if (Program[0][0]==0) ActProg = -1;
  462.         }
  463.     }
  464.  
  465. void SCMD_Jump( int blocks )
  466.     {
  467.     static SCSICMD10 command1 =
  468.         {
  469.         SCSI_CMD_READSUBCHANNEL,
  470.         0,
  471.         0x40,
  472.         0,
  473.         PAD,
  474.         PAD,
  475.         0,
  476.         0,0,
  477.         PAD
  478.         };
  479.  
  480.     static SCSICMD12 command2 =
  481.         {
  482.         SCSI_CMD_PLAYAUDIO12,
  483.         PAD,
  484.         0, 0, 0, 0,
  485.         0, 0, 0, 0,
  486.         PAD,
  487.         PAD,
  488.         };
  489.  
  490.     int err;
  491.     int addr;
  492.  
  493.     command1.b2 = 0x40;
  494.     command1.b3 = 1;
  495.     command1.b6 = 0;
  496.  
  497.     command1.b7 = 255;
  498.     command1.b8 = 255;
  499.  
  500.     if ((err = DoScsiCmd ((UBYTE *) scsi_data, MAX_DATA_LEN,
  501.                           (UBYTE *) &command1, sizeof (command1),
  502.                           (SCSIF_READ | SCSIF_AUTOSENSE))) == 0)
  503.         {
  504.        addr = (scsi_data[8] << 24) | (scsi_data[9] << 16) | (scsi_data[10] << 8) | (scsi_data[11]);
  505.         addr += blocks;
  506.  
  507.         if ((addr>=TOC_Addr[ActTitle-1])&&(addr<TOC_Addr[ActTitle]))
  508.             {
  509.             command2.b2 = (addr&0xFF000000)>>24;
  510.             command2.b3 = (addr&0x00FF0000)>>16;
  511.             command2.b4 = (addr&0x0000FF00)>>8;
  512.             command2.b5 = (addr&0x000000FF);
  513.  
  514.             if (ActProg == -1)
  515.                 {
  516.                 addr = TOC_Addr[TOC_NumTracks]-TOC_Addr[ActTitle-1]-1;
  517.                 }
  518.             else addr = TOC_Addr[ActTitle]-TOC_Addr[ActTitle-1]-1;
  519.  
  520.             command2.b6 = (addr&0xFF000000)>>24;
  521.             command2.b7 = (addr&0x00FF0000)>>16;
  522.             command2.b8 = (addr&0x0000FF00)>>8;
  523.             command2.b9 = (addr&0x000000FF);
  524.  
  525.             DoScsiCmd ((UBYTE *) scsi_data, MAX_DATA_LEN,
  526.                        (UBYTE *) & command2, sizeof (command2),
  527.                        (SCSIF_READ | SCSIF_AUTOSENSE));
  528.             }
  529.         }
  530.     }
  531.  
  532. void SCMD_ReadTitleTime( int settimer )
  533.     {
  534.     static SCSICMD10 command =
  535.         {
  536.         SCSI_CMD_READSUBCHANNEL,
  537.         0,
  538.         0x40,
  539.         0,
  540.         PAD,
  541.         PAD,
  542.         0,
  543.         0,0,
  544.         PAD
  545.         };
  546.  
  547.     int err;
  548.     int microsleft = 950000;
  549.     int addr;
  550.     int slen;
  551.     char Buffer[20];
  552.  
  553.     if (SetNextTitle == 1)
  554.         {
  555.         if (Program[ActProgTitle][ActProg]) SCMD_PlayAudio( ActProgTitle+1 );
  556.         SetNextTitle = 0;
  557.         };
  558.  
  559.     command.b2 = 0x40;
  560.     command.b3 = 1;
  561.     command.b6 = 0;
  562.  
  563.     command.b7 = 255;
  564.     command.b8 = 255;
  565.  
  566.     if ((err = DoScsiCmd ((UBYTE *) scsi_data, MAX_DATA_LEN,
  567.                           (UBYTE *) &command, sizeof (command),
  568.                           (SCSIF_READ | SCSIF_AUTOSENSE))) != 0)
  569.         {
  570.         if (ActStat!=0)
  571.             {
  572.             ActStat=0;
  573.             CleanMainWnd();
  574.             };
  575.         }
  576.     else if ((scsi_data[1] == 0x11) || (scsi_data[1] == 0x12))
  577.         {
  578.         if (ActStat==0)
  579.             {
  580.             SCMD_ReadTOC();
  581.             };
  582.         if (scsi_data[1]==0x11)
  583.             {
  584.             if (ActStat!=1)
  585.                 {
  586.                 DrawPlaySymb( 1 );
  587.                 DrawPrgmSymb( (ActProg!=-1)?1:0 );
  588.                 SetDispStat();
  589.                 };
  590.             ActStat=1;
  591.             }
  592.         else
  593.             {
  594.             if (ActStat!=3)
  595.                 {
  596.                 DrawPlaySymb( 3 );
  597.                 DrawPrgmSymb( (ActProg!=-1)?1:0 );
  598.                 SetDispStat();
  599.                 };
  600.             ActStat=3;
  601.             };
  602.         SetAPen( MainWnd->RPort, 2 );
  603.         SetBPen( MainWnd->RPort, 1 );
  604.  
  605.         if (scsi_data[6]!=ActTitle)
  606.             {
  607.             ActTitle = scsi_data[6];
  608.             InputTitleStat = 0;
  609.             if (ActProg==-1) ActProgTitle = ActTitle;
  610.             sprintf(Buffer, "%02d", ActTitle);
  611.             Move( MainWnd->RPort, 25, 37+offy );
  612.             Text( MainWnd->RPort, Buffer, 2 );
  613.  
  614.             SetAPen( MainWnd->RPort, 1 );
  615.             RectFill( MainWnd->RPort, 25, 52+offy, 258, 64+offy );
  616.             SetAPen( MainWnd->RPort, 2 );
  617.             Move( MainWnd->RPort, 25, 61+offy );
  618.             slen = strlen(TOC_Title[ActTitle-1]);
  619.             Text( MainWnd->RPort, TOC_Title[ActTitle-1], (slen>29)? 29 : slen );
  620.             SetDispStat();
  621.             SetAPen( MainWnd->RPort, 2 );
  622.             };
  623.  
  624.         sprintf(Buffer, "%02d", scsi_data[7]);
  625.      Move( MainWnd->RPort, 52, 37+offy );
  626.      Text( MainWnd->RPort, Buffer, 2 );
  627.  
  628.         addr = (scsi_data[12] << 24) | (scsi_data[13] << 16) | (scsi_data[14] << 8) | (scsi_data[15]);
  629.         sprintf(Buffer, "%02d", addr/75/60 );
  630.      Move( MainWnd->RPort, 80, 37+offy );
  631.      Text( MainWnd->RPort, Buffer, 2 );
  632.  
  633.         sprintf(Buffer, "%02d", (addr/75)%60 );
  634.      Move( MainWnd->RPort, 99, 37+offy );
  635.      Text( MainWnd->RPort, Buffer, 2 );
  636.  
  637.         microsleft = (ActStat==1)?((75 - addr%75)*13333 + 1000):999000;
  638.  
  639.        addr = (scsi_data[8] << 24) | (scsi_data[9] << 16) | (scsi_data[10] << 8) | (scsi_data[11]);
  640.         sprintf(Buffer, "%02d", addr/75/60 );
  641.      Move( MainWnd->RPort, 168, 37+offy );
  642.      Text( MainWnd->RPort, Buffer, 2 );
  643.  
  644.         sprintf(Buffer, "%02d", (addr/75)%60 );
  645.      Move( MainWnd->RPort, 187, 37+offy );
  646.      Text( MainWnd->RPort, Buffer, 2 );
  647.  
  648.         addr = TOC_Addr[scsi_data[6]]-addr;
  649.         if ((addr<80) && (ActProg!=-1))
  650.             {
  651.             microsleft = ((addr<75)?addr:74)*13333 + 100;
  652.             SetNextTitle = 1;
  653.             };
  654.         sprintf(Buffer, "%02d", addr/75/60 );
  655.      Move( MainWnd->RPort, 124, 37+offy );
  656.      Text( MainWnd->RPort, Buffer, 2 );
  657.  
  658.         sprintf(Buffer, "%02d", (addr/75)%60 );
  659.      Move( MainWnd->RPort, 143, 37+offy );
  660.      Text( MainWnd->RPort, Buffer, 2 );
  661.         }
  662.     else if (ActStat != 2)
  663.         {
  664.         if (ActStat==0)
  665.             SCMD_ReadTOC();
  666.         if ((ActStat==1)&&(ActProg!=-1)&&(Program[ActProgTitle][ActProg]!=0))
  667.             {
  668.             SCMD_PlayAudio( ActProgTitle+1 );
  669.             }
  670.         else
  671.             {        
  672.             ActTitle = 0;
  673.             InputTitleStat = 0;
  674.             ActProgTitle = 0;
  675.             DrawPlaySymb( 0 );
  676.             SetDispStat();
  677.             DrawPrgmSymb( (ActProg!=-1)?1:0 );
  678.             SetBPen( MainWnd->RPort, 1 );
  679.             SetAPen( MainWnd->RPort, 1 );
  680.             RectFill( MainWnd->RPort, 25, 52+offy, 258, 64+offy );
  681.             SetAPen( MainWnd->RPort, 2 );
  682.             Move( MainWnd->RPort, 25, 61+offy );
  683.             slen = strlen(TOC_CDTitle);
  684.             Text( MainWnd->RPort, TOC_CDTitle, (slen>29)?29:slen );
  685.  
  686.             Buffer[0]='0';
  687.             Buffer[1]='0';
  688.  
  689.         Move( MainWnd->RPort, 25, 37+offy );
  690.         Text( MainWnd->RPort, Buffer, 2 );
  691.  
  692.          Move( MainWnd->RPort, 52, 37+offy );
  693.          Text( MainWnd->RPort, Buffer, 2 );
  694.  
  695.          Move( MainWnd->RPort, 80, 37+offy );
  696.          Text( MainWnd->RPort, Buffer, 2 );
  697.  
  698.          Move( MainWnd->RPort, 99, 37+offy );
  699.          Text( MainWnd->RPort, Buffer, 2 );
  700.  
  701.          Move( MainWnd->RPort, 168, 37+offy );
  702.          Text( MainWnd->RPort, Buffer, 2 );
  703.  
  704.          Move( MainWnd->RPort, 187, 37+offy );
  705.          Text( MainWnd->RPort, Buffer, 2 );
  706.  
  707.          Move( MainWnd->RPort, 124, 37+offy );
  708.          Text( MainWnd->RPort, Buffer, 2 );
  709.  
  710.          Move( MainWnd->RPort, 143, 37+offy );
  711.          Text( MainWnd->RPort, Buffer, 2 );
  712.          };
  713.         ActStat = 2;
  714.         };
  715.     if (settimer)
  716.         {
  717.         TimerIO->tr_node.io_Command = TR_ADDREQUEST;
  718.         TimerIO->tr_time.tv_secs    = 0;
  719.         TimerIO->tr_time.tv_micro   = microsleft;
  720.         SendIO((struct IORequest *)TimerIO);
  721.         };
  722.     }
  723.  
  724. int SetDispStat( void )
  725.     {
  726.     char  DispStat[20];
  727.     int i;
  728.  
  729.     for (i=0; i<20; i++) DispStat[i] = 0;
  730.     if (ActProg==-1)
  731.         {
  732.         for (i=ActTitle; (i<=TOC_NumTracks) && (i<20); i++)
  733.             DispStat[i-1] = 1;
  734.         }
  735.     else
  736.         {
  737.         for (i=ActProgTitle; Program[i-1][ActProg]!=0; i++)
  738.             {
  739.             if (Program[i-1][ActProg]<19)
  740.                 {
  741.                 DispStat[Program[i-1][ActProg]-1] = 1;
  742.                 }
  743.             else DispStat[19]=1;
  744.             }
  745.         }
  746.     for (i=0; i<20; i++)
  747.         {
  748.         SetAPen( MainWnd->RPort, 1+DispStat[i]*2 );
  749.         Move( MainWnd->RPort, 25+7*i, 65+offy );
  750.         Draw( MainWnd->RPort, 30+7*i, 65+offy );
  751.         Move( MainWnd->RPort, 25+7*i, 71+offy );
  752.         Draw( MainWnd->RPort, 30+7*i, 71+offy );
  753.         };
  754.     }
  755.  
  756.  
  757. void SCSI_Exit( void )
  758.     {
  759.     if (io_ptr)
  760.         {
  761.         CloseDevice ((struct IORequest *) io_ptr);
  762.         DeleteStdIO (io_ptr);
  763.         }
  764.     if (mp_ptr)
  765.         DeletePort (mp_ptr);
  766.     if (scsi_sense)
  767.         FreeMem (scsi_sense, SENSE_LEN);
  768.  
  769.     if (toc_buf)
  770.         FreeMem (toc_buf, MAX_TOC_LEN);
  771.  
  772.     if (scsi_data)
  773.         FreeMem (scsi_data, MAX_DATA_LEN);
  774.     }
  775.  
  776. char SCSI_Init (void)
  777.     {
  778.     if ((scsi_data = (UBYTE *) AllocMem (MAX_DATA_LEN, MEMF_CHIP | MEMF_CLEAR)) == NULL)
  779.         {
  780.         ErrorMsg( "Speicheranforderung fehlgeschlagen" );
  781.         return FALSE;
  782.         }
  783.  
  784.     if ((toc_buf = (UBYTE *) AllocMem (MAX_TOC_LEN, MEMF_CHIP)) == NULL)
  785.         {
  786.         ErrorMsg( "Speicheranforderung fehlgeschlagen" );
  787.         return FALSE;
  788.         }
  789.  
  790.     if ((scsi_sense = (UBYTE *) AllocMem (SENSE_LEN, MEMF_CHIP || MEMF_CLEAR)) == NULL)
  791.         {
  792.         ErrorMsg( "Speicheranforderung fehlgeschlagen" );
  793.         return FALSE;
  794.         }
  795.     if ((mp_ptr = (MSGPORT *) CreatePort (NULL, 0)) == NULL)
  796.         {
  797.         ErrorMsg( "CreatePort fehlgeschlagen" );
  798.         return FALSE;
  799.         }
  800.     if ((io_ptr = (IOSTDREQ *) CreateStdIO (mp_ptr)) == NULL)
  801.         {
  802.         ErrorMsg( "CreateStdIO fehlgeschlagen" );
  803.         return FALSE;
  804.         }
  805.     if (OpenDevice (scsi_dev, scsi_id, (struct IORequest *) io_ptr, 0) != 0)
  806.         {
  807.         ErrorMsg( "Kann SCSI-Device nicht öffnen!\n- Falscher Devicename?\n-Falsche SCSI-ID?" );
  808.         return FALSE;
  809.         }
  810.     return TRUE;
  811.     }
  812.  
  813. int MakeCxObj( CxObj *broker, int nr, char *FiltStr )
  814.     {
  815.     if (filter[nr] = CxFilter( FiltStr ))
  816.         {
  817.         AttachCxObj(broker, filter[nr]);
  818.         if (sender[nr] = CxSender(BrokerMP, 1L))
  819.             {
  820.             AttachCxObj(filter[nr], sender[nr] );
  821.             if (translate[nr] = CxTranslate(NULL))
  822.                 {
  823.                 AttachCxObj(filter[nr], translate[nr]);
  824.                 return( CxObjError( filter[nr] ) );
  825.                 }
  826.             }
  827.         }
  828.     return( 1 );
  829.     }
  830.  
  831. int GetToolTypes(int argc, char **ttarray)
  832.     {
  833.     int err = 0;
  834.  
  835.     if ( ! ( CxBase = OpenLibrary( "commodities.library", 37L )))
  836.         return( 3L );
  837.  
  838.     scsi_dev = ArgString( ttarray, "SCSI_DEV", "scsi.device" );
  839.     scsi_id  = ArgInt( ttarray, "SCSI_ID", 1 );
  840.     SongPath = ArgString( ttarray, "SONGPATH", "" );
  841.     WndPosition = ArgInt( ttarray, "WND_POS", 0 );
  842.     strcpy( FontName, ArgString( ttarray, "FONTNAME", "MCDP_DOT.font" ));
  843.  
  844.     if (BrokerMP = CreateMsgPort())
  845.         {
  846.         newbroker.nb_Port = BrokerMP;
  847.         cxsigflag = 1L << BrokerMP->mp_SigBit;
  848.         newbroker.nb_Pri = (BYTE)ArgInt(ttarray, "CX_PRIORITY", 0);
  849. /*      hotkey = ArgString(ttarray, "CX_POPKEY", "rawkey control lalt <");
  850.         PopUp = ArgString(ttarray, "CX_POPUP", "Yes"); */
  851.         if (broker = CxBroker(&newbroker, NULL))
  852.             {
  853.             err+= MakeCxObj( broker,  0, "control lalt numericpad 0");
  854.             err+= MakeCxObj( broker,  1, "control lalt numericpad 1");
  855.             err+= MakeCxObj( broker,  2, "control lalt numericpad 2");
  856.             err+= MakeCxObj( broker,  3, "control lalt numericpad 3");
  857.             err+= MakeCxObj( broker,  4, "control lalt numericpad 4");
  858.             err+= MakeCxObj( broker,  5, "control lalt numericpad 5");
  859.             err+= MakeCxObj( broker,  6, "control lalt numericpad 6");
  860.             err+= MakeCxObj( broker,  7, "control lalt numericpad 7");
  861.             err+= MakeCxObj( broker,  8, "control lalt numericpad 8");
  862.             err+= MakeCxObj( broker,  9, "control lalt numericpad 9");
  863.             err+= MakeCxObj( broker, 10, "control lalt numericpad .");
  864.             err+= MakeCxObj( broker, 11, "control lalt shift numericpad enter");
  865.             err+= MakeCxObj( broker, 12, "control lalt numericpad /");
  866.             err+= MakeCxObj( broker, 13, "control lalt numericpad *");
  867.             err+= MakeCxObj( broker, 14, "control lalt numericpad -upstroke -");
  868.             err+= MakeCxObj( broker, 15, "control lalt numericpad +");
  869.             err+= MakeCxObj( broker, 16, "control lalt numericpad enter");
  870.             if (err==0)
  871.                 {
  872.                 ActivateCxObj(broker, 1L);
  873.                 return( 0L );
  874.                 }
  875.             }
  876.         }
  877.     ErrorMsg( "Couldn't setup Commodity" );
  878.     return( 2L );
  879.     }
  880.  
  881. void CleanUp( void )
  882.     {
  883.     CxMsg *msg;
  884.  
  885.     if ( DObj ) FreeDiskObject( DObj );
  886.     if ( broker ) DeleteCxObjAll(broker);
  887.     if ( BrokerMP )
  888.         {
  889.         while (msg = (CxMsg *)GetMsg(BrokerMP))
  890.             ReplyMsg((struct Message *)msg);
  891.         DeletePort( BrokerMP );
  892.         };
  893.     if ( CxBase ) CloseLibrary( CxBase );
  894.     }
  895.  
  896. ProcessCxMsg( CxMsg *msg )
  897.     {
  898.     ULONG msgid, msgtype;
  899.     int   nr;
  900.  
  901.     msgid = CxMsgID( msg );
  902.     msgtype = CxMsgType( msg );
  903.  
  904.     switch(msgtype)
  905.         {
  906.         case CXM_IEVENT:
  907.             if (msgid == 1L)
  908.                 {
  909.                 nr = 0;
  910.                 switch (((struct InputEvent *)CxMsgData(msg))->ie_Code)
  911.                     {
  912.                     case 67:
  913.                         if (ActStat!=1) SCMD_PlayAudio( 1 );
  914.                         break;
  915.                     case 60:
  916.                         SCMD_Stop();
  917.                         break;
  918.                     case 74:
  919.                         if (ActStat==1) SCMD_PlayAudio( ActProgTitle-1 );
  920.                         break;
  921.                     case 94:
  922.                         if (ActStat==1) SCMD_PlayAudio( ActProgTitle+1 );
  923.                         break;
  924.                     case 93:
  925.                         ActProg=-1;
  926.                         DrawPrgmSymb( 0 );
  927.                         InputTitleStat = 1;
  928.                         SetAPen( MainWnd->RPort, 2 );
  929.                         SetBPen( MainWnd->RPort, 1 );
  930.                         Move( MainWnd->RPort, 25, 37+offy );
  931.                         Text( MainWnd->RPort, "__", 2 );
  932.                         break;
  933.                     case 15:
  934.                         nr = 10;
  935.                         break;
  936.                     case 29:
  937.                         nr = 1; 
  938.                         break;
  939.                     case 30:
  940.                         nr = 2;
  941.                         break;
  942.                     case 31:
  943.                         nr = 3; 
  944.                         break;
  945.                     case 45:
  946.                         nr = 4; 
  947.                         break;
  948.                     case 46:
  949.                         nr = 5; 
  950.                         break;
  951.                     case 47:
  952.                         nr = 6; 
  953.                         break;
  954.                     case 61:
  955.                         nr = 7; 
  956.                         break;
  957.                     case 62:
  958.                         nr = 8; 
  959.                         break;
  960.                     case 63:
  961.                         nr = 9; 
  962.                         break;
  963.                     case 92:
  964.                         SCMD_Eject();
  965.                         break;
  966.                     }
  967.                 if (nr!=0)
  968.                     {
  969.                     switch( InputTitleStat )
  970.                         {
  971.                         char a;
  972.                         case 0:
  973.                             SCMD_PlayAudio( nr );
  974.                             break;
  975.                         case 1:
  976.                             if (nr < 10)
  977.                                 {
  978.                                 InputTitle = nr*10;
  979.                                 }
  980.                             else InputTitle = 0;
  981.                             a = (InputTitle/10)+48;
  982.                             SetAPen( MainWnd->RPort, 2 );
  983.                             SetBPen( MainWnd->RPort, 1 );
  984.                             Move( MainWnd->RPort, 25, 37+offy );
  985.                             Text( MainWnd->RPort, &a, 1 );
  986.                             InputTitleStat = 2;
  987.                             break;
  988.                         case 2:
  989.                             if (nr < 10)
  990.                                 {
  991.                                 InputTitle += nr;
  992.                                 };
  993.                             InputTitleStat = 0;
  994.                             SCMD_PlayAudio( InputTitle );
  995.                             break;
  996.                         }
  997.                     }
  998.                 };
  999.             break;
  1000.         case CXM_COMMAND:
  1001.             switch(msgid)
  1002.                 {
  1003.                 case CXCMD_DISABLE:
  1004.                     ActivateCxObj(broker, 0L);
  1005.                     break;
  1006.                 case CXCMD_ENABLE:
  1007.                     ActivateCxObj(broker, 1L);
  1008.                     break;
  1009.                 case CXCMD_DISAPPEAR:
  1010.                     break;
  1011.                 case CXCMD_APPEAR:
  1012.                     break;
  1013.                 case CXCMD_UNIQUE:
  1014.                     break;
  1015.                 case CXCMD_KILL:
  1016.                     Wait( 1<<TimerMP->mp_SigBit );
  1017.                     GetMsg(TimerMP);
  1018.                 SCSI_Exit();
  1019.                     TimerExit();
  1020.                     CleanUp();
  1021.                     CloseMainWnd();
  1022.                 exit(0);
  1023.                     break;
  1024.                 };
  1025.             break;
  1026.         };
  1027.     ReplyMsg((struct Message *)msg);
  1028.     }
  1029.  
  1030. wbmain(struct WBStartup *WBS)
  1031.     {
  1032.     struct WBArg *WA;
  1033.     BPTR DL;
  1034.     char **tt;
  1035.     
  1036.     WA = &WBS->sm_ArgList[WBS->sm_NumArgs-1];
  1037.     DL = CurrentDir( WA->wa_Lock );
  1038.     if (DObj=(struct DiskObject *)GetDiskObject(WA->wa_Name))
  1039.         {
  1040.         CurrentDir( DL );
  1041.         tt = DObj->do_ToolTypes;
  1042.         commonmain(0, tt);
  1043.         };
  1044.     }
  1045.  
  1046. main(int argc, char **argv)
  1047.     {
  1048.     commonmain(argc, argv);
  1049.     }
  1050.  
  1051. commonmain (int argc, char **argv)
  1052.     {
  1053.     ULONG  GClass;
  1054.     USHORT GCode;
  1055.     UWORD  GQual;
  1056.     ULONG  GTimeS;
  1057.     ULONG  GTimeM;
  1058.     struct Gadget *GList = 0l;
  1059.     WORD   GMouseY;
  1060.     ULONG  Signal;
  1061.     struct IntuiMessage  *msg;
  1062.     CxMsg *cxmsg;
  1063.  
  1064.     int j = 0, i = 0;
  1065.     int returnvalue = 0;
  1066.     int RefreshTimer = 8;
  1067.  
  1068.     GetToolTypes(argc, argv);
  1069.  
  1070.     if (SCSI_Init() && TimerInit())
  1071.         {
  1072.         if (OpenMainWnd(WndPosition)==0)
  1073.             {
  1074.             SCMD_ReadTitleTime(1);
  1075.             for(;;)
  1076.                 {
  1077.                 Signal = Wait( (1<<MainWnd->UserPort->mp_SigBit)|(1<<TimerMP->mp_SigBit)|cxsigflag );
  1078.                 if (Signal & (1<<TimerMP->mp_SigBit))
  1079.                     {
  1080.                     GetMsg(TimerMP);
  1081.                     SCMD_ReadTitleTime(1);
  1082.                     };
  1083.                 if (Signal & cxsigflag)
  1084.                     {
  1085.                 while ( cxmsg = (CxMsg *)GetMsg(BrokerMP))
  1086.                     ProcessCxMsg( cxmsg );
  1087.                 };
  1088.                 if (Signal & (1<<MainWnd->UserPort->mp_SigBit))
  1089.                     {
  1090.                     while ( msg = (struct IntuiMessage *) GetMsg( MainWnd->UserPort ) )
  1091.                         {
  1092.                         GClass  = msg->Class;
  1093.                         GCode   = msg->Code;
  1094.                         GQual   = msg->Qualifier;
  1095.                         if (GClass & (GADGETDOWN | GADGETUP | MOUSEMOVE) )
  1096.                             GList   = (struct Gadget *) msg->IAddress;
  1097.                         GMouseY = msg->MouseY;
  1098.                 GTimeS  = msg->Seconds;
  1099.                 GTimeM  = msg->Micros;
  1100.                 ReplyMsg(msg);
  1101.  
  1102.                 switch (GClass)
  1103.                     {
  1104.                     case IDCMP_CLOSEWINDOW :
  1105.                                 Wait( 1<<TimerMP->mp_SigBit );
  1106.                                 GetMsg(TimerMP);
  1107.                         SCSI_Exit();
  1108.                                 TimerExit();
  1109.                                 CleanUp();
  1110.                                 CloseMainWnd();
  1111.                         exit(0);
  1112.                         break;
  1113.                     case IDCMP_GADGETUP    :
  1114.                                 switch (GList->GadgetID)
  1115.                                     {
  1116.                                     case 19: ActProg=-1;
  1117.                                              DrawPrgmSymb( 0 );
  1118.                                              InputTitleStat = 1;
  1119.                                              SetAPen( MainWnd->RPort, 2 );
  1120.                                              SetBPen( MainWnd->RPort, 1 );
  1121.                                              Move( MainWnd->RPort, 25, 37+offy );
  1122.                                              Text( MainWnd->RPort, "__", 2 );
  1123.                                              break;
  1124.                                     case 20: TitleList();
  1125.                                              ShowCDTitle();
  1126.                                              break;
  1127.                                     case 21: ProgList();
  1128.                                              break;
  1129.                                     case 22: if (ActProg==-1)
  1130.                                                  {
  1131.                                                  ActProg = 0;
  1132.                                                  DrawPrgmSymb( 1 );
  1133.                                                  }
  1134.                                              break;
  1135.                                     case 23: if (ActStat==3)
  1136.                                                  {
  1137.                                                  SCMD_PauseResume();
  1138.                                                  }
  1139.                                              else if (ActStat!=1) SCMD_PlayAudio( 1 );
  1140.                                              break;
  1141.                                     case 24: SCMD_PauseResume();
  1142.                                              break;
  1143.                                     case 25: SCMD_Stop();
  1144.                                              break;
  1145.                                     case 26: if (ActStat==1) SCMD_PlayAudio( ActProgTitle-1 );
  1146.                                              break;
  1147.                                     case 27: if (ActStat==1) SCMD_PlayAudio( ActProgTitle+1 );
  1148.                                              break;
  1149.                                     case 28: if (ActStat==1) SCMD_Jump( -750 );
  1150.                                              break;
  1151.                                     case 29: if (ActStat==1) SCMD_Jump( 750 );
  1152.                                              break;
  1153.                                     case 30: SCMD_Eject();
  1154.                                              break;
  1155.                                     default: if ((ActProg==-1)&&(GList->GadgetID < 19))
  1156.                                                  {
  1157.                                                  switch( InputTitleStat )
  1158.                                                      {
  1159.                                                      char a;
  1160.                                                      case 0:
  1161.                                                          SCMD_PlayAudio( GList->GadgetID+1 );
  1162.                                                          break;
  1163.                                                      case 1:
  1164.                                                          if (GList->GadgetID < 9)
  1165.                                                              {
  1166.                                                              InputTitle = (GList->GadgetID+1)*10;
  1167.                                                              }
  1168.                                                          else InputTitle = 0;
  1169.                                                          a = (InputTitle/10)+48;
  1170.                                                          SetAPen( MainWnd->RPort, 2 );
  1171.                                                          SetBPen( MainWnd->RPort, 1 );
  1172.                                                          Move( MainWnd->RPort, 25, 37+offy );
  1173.                                                          Text( MainWnd->RPort, &a, 1 );
  1174.                                                          InputTitleStat = 2;
  1175.                                                          break;
  1176.                                                      case 2:
  1177.                                                          if (GList->GadgetID < 9)
  1178.                                                              {
  1179.                                                              InputTitle += GList->GadgetID+1;
  1180.                                                              };
  1181.                                                          InputTitleStat = 0;
  1182.                                                          SCMD_PlayAudio( InputTitle );
  1183.                                                          break;
  1184.                                                      }
  1185.                                                  }
  1186.                                              else if ((ActProg!=-1)&&(GList->GadgetID < 8))
  1187.                                                  {
  1188.                                                  ActProg = GList->GadgetID + 1;
  1189.                                                  }
  1190.                                              break;
  1191.                                     };
  1192.                                 SCMD_ReadTitleTime(0);
  1193.                                 RefreshTimer = 8;
  1194.                         break;
  1195.                     };
  1196.                 };
  1197.                     };
  1198.                 };
  1199.             };
  1200.         }
  1201.     SCSI_Exit();
  1202.     TimerExit();
  1203.     CleanUp();
  1204.     CloseMainWnd();
  1205.     exit( 0 );
  1206.     }
  1207.